//
//  vdEvent.h
//  Void Dead
//
//  Created by Sidney Just on 27.11.09.
//
//  Copyright © 2009 by Sidney Just
//  Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated 
//  documentation files (the "Software"), to deal in the Software without restriction, including without limitation 
//  the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, 
//  and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
//  The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
//  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 
//  INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR 
//  PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE 
//  FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 
//  ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//

#import <Foundation/Foundation.h>
#import "vdHeader.h"

// Engine Events
@class vdEventReceiver;


#pragma mark -
#pragma mark Engine events
typedef enum {
	vdEngineFrameDidEnd,
	vdEngineFrameDidBegin,
	vdEngineFrameWillEnd,
	vdEngineFrameWillBegin
} vdEngineEventType;

/**
 * This struct will be added to the data pointer if the message is from type vdEngineEvent.
 **/
typedef struct {
	/**
	 * The event type. Possible types are:
	 * <br>vdEngineFrameDidEnd: The engine has flushed the framebuffer content to the screen and the delta time has been calculated
	 * <br>vdEngineFrameDidBegin: The engine has begun with the scene, but no object has been drawn into the framebuffer yet
	 * <br>vdEngineFrameWillBegin: The engine has not bound the framebuffer yet
	 * <br>vdEngineFrameWillEnd: The engine has not flushed the framebuffer yet, but has finished all drawing.
	 **/
	vdEngineEventType event;
} vdEngineMessage;

#pragma mark -
#pragma mark Input Events
// Input Events
typedef enum {
	vdTouchesBegan,
	vdTouchesMoved,
	vdTouchesEnded,
	vdTouchesCancelled
} vdInputType;

/**
 * This struct will be added to the data pointer if the message is from type vdInputEvent.
 **/
typedef struct {
	/**
	 * Array with the position of the touches. The array has the size of the touch count
	 **/
	CGPoint     *touch;
	
	/**
	 * Array with the difference between the old touches and the new touches. The array has the size of the touch count and is only available if the event isn't vdTouchesBegan!
	 **/
	CGPoint     *diff;
	
	/**
	 * The event type. Possible types are:
	 * <br>vdTouchesBegan: The touch sequence has begun
	 * <br>vdTouchesMoved: The touch sequence has been moved
	 * <br>vdTouchesEnded: The touch sequence has been ended
	 * <br>vdTouchesCancelled: The touch sequence has been cancelled
	 **/
	vdInputType event;
	
	/**
	 * The touches on the screen. This value is always between 1 and 12.
	 **/
	int         touchCount;
} vdInputMessage;

#pragma mark -
#pragma mark Error Events

typedef enum {
	vdEngineError,
	vdOpenGLError
} vdErrorType;

/**
 * This struct will be added to the data pointer if the message is from type vdErrorEvent.
 **/
typedef struct {
	/**
	 * The event type. Possible types are:
	 * <br>vdEngineError: The error has been generated from the engine
	 * <br>vdOpenGLError: The error has been generated from OpenGL
	 **/
	vdErrorType event;
	
	/**
	 * The OpenGL error. This is only available if the event is vdOpenGLError!
	 **/
	GLenum glError;
	
	/**
	 * The Engine error. This is only available if the event is vdEngineError!
	 * Possible values are:
	 * <br>vdNoError: There is no error (this type won't be thrown!)
	 * <br>vdFallback: The engine has been switched to the next lower OpenGL ES version because the wanted version isn't supported
	 * <br>vdShaderUnsupported This indicates that you want to load a shader from an device or OS that doesn't support shaders or OpenGL ES 2.0.
	 * <br>vdShaderFailedToCompileVertexShader There was an error while compiling the vertex shader data
	 * <br>vdShaderFailedToCompileFragmentShader There was an error while compiling the fragment shader data
	 * <br>vdShaderFailedToLinkShader There was an error while linking the shader program
	 * <br>vdShaderFailedToLoadVertexShader There was an error while loading the vertex shader
	 **/
	vdEngineErrorType vdError;
} vdErrorMessage;

#pragma mark -
#pragma mark Events
// Event
typedef enum {
	vdNone = 0,
	vdEngineEvent = 1,
	vdInputEvent = 2,
	vdErrorEvent = 4,
	vdUserEvent = 8
} vdEventType;

/**
 * This struct is the base for all events. It contains the event type and the event data.
 **/
typedef struct {
	/**
	 * The event type. Possible types are:
	 * <br>vdEngineEvent: The event comes from the engine. The data pointer will allways contain a vdEngineMessage struct.
	 * <br>vdInputEvent: The event comes from user input. The data pointer will allways contain a vdInputMessage struct.
	 * <br>vdUserEvent: The event comes not from void dead. The data pointer can contain anything!
	 **/
	vdEventType type;
	
	/**
	 * The data of the event
	 **/
	void		*data;
	
	/**
	 * The sender of the event
	 **/
	id			sender;
} vdEventMessage;

/**
 * This class handles all incoming events from the engine and the user and pushes them to the registered receivers.
 **/
@interface vdEventHandler : NSObject {
	@private
	vdEventReceiver **receiver;
	int				receiverCount;
}

/**
 * Returns the event handler.
 @return Pointer the the event handler
 **/
+ (vdEventHandler *)sharedEventHandler;

/**
 * Fires the given vdEventMessage to the receivers.
 @param aMessage The message you want to fire
 **/
- (void)fireEvent:(vdEventMessage *)aMessage;

/**
 * Creates a vdEventMessage out of your passed values and fires the message to the receivers
 @param aType The message type (if you want to use own events, it's recommended to use vdUserEvent as type!)
 @param sender The sender of the message
 @param aData The data that you want push with the message
 **/
- (void)fireEvent:(vdEventType)aType sender:(id)sender data:(void *)aData;

/**
 * Adds the given receiver to the receiver list. You need to add your receiver if you want to retreive events
 @param aReceiver The receiver you want to add
 **/
- (void)addReceiver:(vdEventReceiver *)aReceiver;

/**
 * Removes the given receiver from the receiver list.
 @param aReceiver The receiver you want to remove
 **/
- (void)removeReceiver:(vdEventReceiver *)aReceiver;


@end
